package fr.ece.ing4.si.MonteCarloGUI;

import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Insets;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.border.EmptyBorder;

import fr.ece.ing4.si.MonteCarloConcur.MonteCarloConcur;
import fr.ece.ing4.si.MonteCarloSeq.MonteCarloSeq;
import fr.ece.ing4.si.MonteCarloSet.Set;

public class myGUI extends JFrame implements ActionListener {

	//the different elements of the GUI
	private JLabel result, result2, result3, result4, ask;
	private JComboBox combobox;
	private JPanel panel;
	private JButton quitButton, buttonSeq, buttonConcur;
	
	private ArrayList<Set> Sets;     //all the sets to gives in the combobox

	//constructor, set the Sets and the type, and launch the initialisation of the GUI
	public myGUI(ArrayList<Set>Sets) {
		this.Sets = new ArrayList<Set>(Sets);
		initUI();
	}

	public final void initUI() {

		//initialisation if the different graphical elements
		panel = new JPanel();
		panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
		panel.setBorder(new EmptyBorder(new Insets(40, 60, 40, 60)));

		quitButton = new JButton("Quit");
		quitButton.addActionListener(this);
		quitButton.setAlignmentX(Component.CENTER_ALIGNMENT);
		
		buttonSeq = new JButton("Single Threaded");
		buttonSeq.addActionListener(this);
		buttonSeq.setAlignmentX(Component.CENTER_ALIGNMENT);
		
		buttonConcur = new JButton("Multi Threaded");
		buttonConcur.addActionListener(this);
		buttonConcur.setAlignmentX(Component.CENTER_ALIGNMENT);

		result = new JLabel("");
		result.setAlignmentX(Component.CENTER_ALIGNMENT);
		
		result2 = new JLabel("");
		result2.setAlignmentX(Component.CENTER_ALIGNMENT);
		
		result3 = new JLabel("");
		result3.setAlignmentX(Component.CENTER_ALIGNMENT);
		
		result4 = new JLabel("");
		result4.setAlignmentX(Component.CENTER_ALIGNMENT);

		ask = new JLabel("Please choose a set of arguments : ");
		ask.setAlignmentX(Component.CENTER_ALIGNMENT);

		combobox = new JComboBox();
		for (Set s : Sets) {
			combobox.addItem(s.toString());
		}
		combobox.setSelectedIndex(-1);
		combobox.setPreferredSize(new Dimension(520, 22));
		combobox.setMaximumSize(new Dimension(520, 22));

		panel.add(ask);
		panel.add(Box.createRigidArea(new Dimension(0, 7)));
		panel.add(combobox);
		panel.add(Box.createRigidArea(new Dimension(0, 25)));
		panel.add(result);
		panel.add(Box.createRigidArea(new Dimension(0, 15)));
		panel.add(result2);
		panel.add(Box.createRigidArea(new Dimension(0, 15)));
		panel.add(result3);
		panel.add(result4);
		panel.add(Box.createRigidArea(new Dimension(0, 25)));
		panel.add(buttonSeq);
		panel.add(Box.createRigidArea(new Dimension(0, 15)));
		panel.add(buttonConcur);
		panel.add(Box.createRigidArea(new Dimension(0, 15)));
		panel.add(quitButton);
		panel.add(Box.createRigidArea(new Dimension(0, 15)));

		add(panel);
		pack();

		//window configuration
		setTitle("Monte Carlo Exercise -- Mamessier - Rigaudiere");
		setSize(700, 400);
		setLocationRelativeTo(null);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
	}

	//when we click on one of the two buttons
	public void actionPerformed(ActionEvent e) {
		JButton button = (JButton) e.getSource();
		//if button Quit, we exit
		if(button == quitButton)
			System.exit(0);
		//if button ExecMC, we calculate the value with montecarlo
		else {	
			int index = combobox.getSelectedIndex();
			Double resultMC = 0.0;
			//Double resultMC2 = 0.0;
			final Set selectedSet = Sets.get(index);
			
			//change the cursor type to indicate that it is in process
			setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
			
			//start the time
			final long start = System.nanoTime();
			
			//if single threaded
			if(button == buttonSeq)
			{
				//just call the montecarlo function and retrieve the value
				resultMC = new MonteCarloSeq().MonteCarloStandardOption(selectedSet.getCallPutFlag(), 
						selectedSet.getS(), selectedSet.getX(), selectedSet.getT(), selectedSet.getR(), 
						selectedSet.getB(), selectedSet.getV(), selectedSet.getnSteps(), 
						selectedSet.getnSimulations());
			}
			
			//if multi threaded
			else if(button == buttonConcur)
			{
				//find the number of core and of threads
				final int numberOfCores = Runtime.getRuntime().availableProcessors();
				final double blockingCoefficient = 0.;
				final int poolSize = (int) (numberOfCores / (1 - blockingCoefficient));
				
				result3.setText("Number of Core : " + numberOfCores);
				result4.setText("Number of threads : " + poolSize);
				
				resultMC = new MonteCarloConcur().totalMonteCarlo(selectedSet.getCallPutFlag(), 
						selectedSet.getS(), selectedSet.getX(), selectedSet.getT(), selectedSet.getR(), 
						selectedSet.getB(), selectedSet.getV(), selectedSet.getnSteps(), 
						selectedSet.getnSimulations(), poolSize);
			}
			final long end = System.nanoTime();
			
			//display the result
			result.setText("The result is : " + resultMC);
			result2.setText("Time (seconds) taken " + (end - start)/1.0e9);
			
			//change the cursor to indicate that the calculation is over
			setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
		}
	}
}
